package com.wyr.dynamic_proxy.config;

import com.wyr.dynamic_proxy.service.HelloService;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Configuration
//@EnableAspectJAutoProxy
@ComponentScan("com.wyr.dynamic_proxy")
public class MyConfig {

    @Bean
    public ProxyFactoryBean helloService(){
        HelloService helloService = new HelloService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(helloService);
        proxyFactoryBean.addAdvice(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println("before.......");
            }
        });
        proxyFactoryBean.setInterceptorNames("myAroundAdvice");
        return proxyFactoryBean;
    }

    @Bean
    public MethodInterceptor myAroundAdvice(){
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object res = invocation.proceed();
                System.out.println("after...");
                return res;
            }
        };
    }

    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator(){
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setBeanNames("helloS*");
        beanNameAutoProxyCreator.setInterceptorNames("myAroundAdvice");
        beanNameAutoProxyCreator.setProxyTargetClass(true);
        return beanNameAutoProxyCreator;
    }


    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor(){
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.addMethodName("hello");
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(myAroundAdvice());
        return advisor;
    }

    /**
     * 如果和@EnableAspectJAutoProxy同时存在，会出现叠加代理
     *
     * DefaultAdvisorAutoProxyCreator会去通过DefaultAdvisorAutoProxyCreator会直接去找所有Advisor类型的Bean，
     * 根据Advisor中的 PointCut和Advice信息，确定要代理的Bean以及代理逻辑。
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        return defaultAdvisorAutoProxyCreator;
    }
}
